﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Ndo
{
    public static class BitwiseUtilities
    {
        #region 8bits
        public static unsafe short UInt8ToInt8(byte v)
        {
            return *((sbyte*)&v);
        }
        public static unsafe short Int8ToUInt8(sbyte v)
        {
            return *((byte*)&v);
        }
        #endregion

        #region 16bits
        public static unsafe short UInt16ToInt16(ushort v)
        {
            return *((short*)&v);
        }
        public static unsafe short CharToInt16(char v)
        {
            return *((short*)&v);
        }
        public static unsafe ushort Int16ToUInt16(short v)
        {
            return *((ushort*)&v);
        }
        public static unsafe ushort CharToUInt16(char v)
        {
            return *((ushort*)&v);
        }
        public static unsafe ushort Int16ToChar(short v)
        {
            return *((char*)&v);
        }
        public static unsafe ushort UInt16ToChar(ushort v)
        {
            return *((char*)&v);
        }
        #endregion

        #region 32bits
        public static unsafe int UInt32ToInt32(uint v)
        {
            return *((int*)&v);
        }
        public static unsafe int FloatToInt32(float v)
        {
            return *((int*)&v);
        }
        public static unsafe uint Int32ToUInt32(int v)
        {
            return *((uint*)&v);
        }
        public static unsafe uint FloatToUInt32(float v)
        {
            return *((uint*)&v);
        }
        public static unsafe float Int32ToFloat(int v)
        {
            return *((float*)&v);
        }
        public static unsafe float UInt32ToFloat(uint v)
        {
            return *((float*)&v);
        }
        #endregion

        #region 64bits
        public static unsafe long DoubleToInt64(double v)
        {
            return *((long*)&v);
        }
        public static unsafe double Int64ToDouble(long v)
        {
            return *((double*)&v);
        }
        #endregion

        public const int SingleFloatBiase = 127;
        public const int SingleFloatExponentBitCount = 8;
        public const int SingleFloatMantissaBitCount = 23;
        public const int DoubleFloatBiase = 1023;
        public const int DoubleFloatExponentBitCount = 11;
        public const int DoubleFloatMantissaBitCount = 52;
        public static unsafe bool GetExponentMantissa(float f, out int exponent, out int mantissa)
        {
            if(f != f)
            {
                exponent = 0;
                mantissa = 0;
                return false;
            }
            int a = *((int*)&f);
            mantissa = a & ((1 << SingleFloatMantissaBitCount)-1);
            exponent = (a >> SingleFloatMantissaBitCount) & ((1 << SingleFloatExponentBitCount)-1);
            if (exponent == ((1 << SingleFloatExponentBitCount) - 1))
            {
                exponent = a >> (SingleFloatExponentBitCount+SingleFloatMantissaBitCount-1);//{+1,-1}
                return false;
            }
            if (exponent != 0)
                mantissa |= (1 << SingleFloatMantissaBitCount);
            else
                exponent++; 
            if (a < 0)
                mantissa = -mantissa;
            exponent -= SingleFloatBiase + SingleFloatMantissaBitCount;
            return true;
        }
        public static unsafe bool GetExponentMantissa(double f, out int exponent, out long mantissa)
        {
            if (f != f)
            {
                exponent = 0;
                mantissa = 0;
                return false;
            }
            long a = *((long*)&f);
            mantissa = a & ((1L << DoubleFloatMantissaBitCount) - 1);
            exponent = (int)(a >> DoubleFloatMantissaBitCount) & ((1 << DoubleFloatExponentBitCount) - 1);
            if (exponent == ((1 << DoubleFloatExponentBitCount) - 1))
            {
                exponent = (int)(a >> (DoubleFloatExponentBitCount + DoubleFloatMantissaBitCount - 1));//{+1,-1}
                return false;
            }
            if (exponent != 0)
                mantissa |= (1L << DoubleFloatMantissaBitCount);
            else
                exponent++;
            if (a < 0)
                mantissa = -mantissa;
            exponent -= DoubleFloatBiase + DoubleFloatMantissaBitCount;
            return true;
        }
        public static unsafe float GetSingleByExponentMantissa(int exponent, int mantissa)
        {
            if (mantissa == 0L)
                return 0.0f;
            exponent += SingleFloatBiase + SingleFloatMantissaBitCount;
            //防止加减法溢出
            if (exponent > (1 << SingleFloatExponentBitCount) + SingleFloatMantissaBitCount)
            {
                if (mantissa < 0)
                    return float.NegativeInfinity;
                return float.PositiveInfinity;
            }
            if (exponent < -32)
                return 0.0f;
            int a = 0;
            if (mantissa < 0)
            {
                a = 1 << 31;
                while (mantissa <= -(1 << (SingleFloatMantissaBitCount + 1)))
                {
                    mantissa >>= 1;
                    exponent++;
                }
                mantissa = -mantissa;
            }
            else
            {
                while (mantissa >= (1L << (SingleFloatMantissaBitCount + 1)))
                {
                    mantissa >>= 1;
                    exponent++;
                }
            }
            while (mantissa < (1L << SingleFloatMantissaBitCount))
            {
                mantissa <<= 1;
                exponent--;
            }
            if (exponent <= 0)
            {
                mantissa >>= 1;
                while (exponent < 0)
                {
                    mantissa >>= 1;
                    exponent++;
                }
            }
            mantissa &= (1 << SingleFloatMantissaBitCount) - 1;
            a |= (exponent << SingleFloatMantissaBitCount) | mantissa;
            return *((float*)&a);
        }
        public static unsafe double GetDoubleByExponentMantissa(int exponent, long mantissa)
        {
            if(mantissa == 0L)
                return 0.0;
            exponent += DoubleFloatBiase + DoubleFloatMantissaBitCount;
            //防止加减法溢出
            if(exponent>(1<<DoubleFloatExponentBitCount)+DoubleFloatMantissaBitCount)
            {
                if(mantissa<0)
                    return double.NegativeInfinity;
                return double.PositiveInfinity;
            }
            if(exponent<-64)
                return 0.0;
            long a = 0L;
            if (mantissa < 0)
            {
                a = 1L << 63;
                while(mantissa<=-(1L<<(DoubleFloatMantissaBitCount+1)))
                {
                    mantissa >>= 1;
                    exponent++;
                }
                mantissa = -mantissa;
            }
            else
            {
                while(mantissa>=(1L<<(DoubleFloatMantissaBitCount+1)))
                {
                    mantissa >>= 1;
                    exponent++;
                }
            }
            while (mantissa < (1L << DoubleFloatMantissaBitCount))
            {
                mantissa <<= 1;
                exponent--;
            }
            if(exponent<=0)
            {
                mantissa >>= 1;
                while (exponent < 0)
                {
                    mantissa >>= 1;
                    exponent++;
                }
            }
            mantissa &= (1L << DoubleFloatMantissaBitCount) - 1L;
            a |= (((long) exponent) << DoubleFloatMantissaBitCount) | mantissa;
            return *((double*)  &a);
        }
    }
}
